﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.Data;

using agvcontroller.Common;
using agvcontroller.Common.DataBase;
using agvcontroller.Driver;
using agvcontroller.Log;

namespace agvcontroller.Control
{
    public delegate void deleReportPosition(object sender, int nodeNo);
    public delegate void deleReportConnection(object sender, enumConnect connect);
    public delegate void deleReportOperation(object sender, enumOperation operation);
    public delegate void deleReportCommunication(object sender, enumCommnication communication);
    public delegate void deleReportAlarm(object sender, int alarmId);
    public delegate void deleAcceptVehicleJob(object sender, string vehiclejobId);
    public delegate void deleRejectVehicleJob(object sender, string vehiclejobId);
    public delegate void deleCompletedVehicleJob(object sender, string vehiclejobId);
    public delegate void deleRequestRoute(object sender, int cmdId);
    public delegate void deleReportVehicleInfo(object sender, stVehicleInfo info);
    public delegate void deleReportInterlockSignal(object sender, List<int> interlock);
    public delegate void deleRcvMsg(object sender, string msg); //test

    public class CVehicle : IDisposable
    {
        #region event
        //test
        public event deleRcvMsg onRcvMsg;

        public event deleReportPosition onReportPosition;
        public event deleReportConnection onReportConnection;
        public event deleReportCommunication onReportCommunication;
        public event deleReportOperation onReportOperation;
        public event deleReportAlarm onReportAlarm;
        public event deleAcceptVehicleJob onAcceptVehicleJob;
        public event deleRejectVehicleJob onRejectVehicleJob;
        public event deleCompletedVehicleJob onCompletedVehicleJob;
        public event deleRequestRoute onRequestRoute;
        public event deleReportVehicleInfo onReportVehicleInfo;
        public event deleReportInterlockSignal onReportInterlockSignal;
        #endregion event

        #region Property
        public int ID { get; set; }

        public string Name { get; set; }

        public enumConnect Connection
        {
            get;
            set;
        }

        public enumCommnication Communication
        {
            get;
            set;
        }


        public enumContolState Control
        {
            get;
            set;
        }

        public enumOperation Operation
        {
            get;
            set;
        }

        public enumVehicleDirect Direct
        {
            get { return Direct; }
        }

        public int Alarm
        {
            get { return Alarm; }
        }

        public enumVehicleDriver Driver
        {
            get { return Driver; }
        }

        public bool Use
        {
            get;
            set;
        }

        public int PreNode
        {
            get { return PreNode; }
        }

        public int CurNode
        {
            get { return CurNode; }
        }

        public int NextNode
        {
            get { return NextNode; }
        }

        public int BatteryLevel
        {
            get { return BatteryLevel; }
        }

        public bool BatteryLow
        {
            get { return BatteryLow; }
        }

        public int BatteryLowLevel
        {
            get;
            set;
        }

        public string EjectType
        {
            get;
            set;
        }

        public string CommType
        {
            get;
            set;
        }

        public string GuideType
        {
            get;
            set;
        }

        public List<int> SpeedSet
        {
            get { return SpeedSet; }
        }

        public int Speed
        {
            get { return Speed; }
        }

        public int Encoder
        {
            get { return Encoder; }
        }

        public bool CanForward
        {
            get;
            set;
        }

        public bool CanBackWard
        {
            get;
            set;
        }

        public bool CanRight
        {
            get;
            set;
        }

        public bool CanLeft
        {
            get;
            set;
        }

        public bool CanSideRight
        {
            get;
            set;
        }

        public bool CanSideLeft
        {
            get;
            set;
        }

        public int SetSpeedNo
        {
            get;
            set;
        }

        public int Port
        {
            get;
            set;
        }

        public IPAddress VehicleIP
        {
            get;
            set;
        }

        public IPAddress AGVCIP
        {
            get;
            set;
        }
        #endregion Property

        CVehicleSocketDriver SocketDriver;
        private bool disposed = false;
        Timer tmrStatus;

        Logger Log;

        public void Dispose()
        {
            Dispose(true);
 
            // 가비지컬렉터가 수동으로 작동되지 않게 설정한다.
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if (disposing)
                {
                }

                // Note disposing has been done.
                disposed = true;

            }
        }

        public CVehicle(string name)
        {
            Name = name;

            tmrStatus = new Timer(new TimerCallback(Tick), null, 1000, Timeout.Infinite);

            Log = new Logger(this.Name);
        }
        ~CVehicle()
        {
            Dispose(false);
        }

        public virtual int InitModule()
        {
            SocketDriver = new CVehicleSocketDriver(AGVCIP, VehicleIP, Port);

            if (SocketDriver.StartListen()==0)
                Connection= enumConnect.CONNECTION;

            RegisterEvent();

            Log.Info("Initial Module");

            return CReturnCode.SUCCESS;
        }

        public void Tick(object state)
        {
            //Connection = SocketDriver.Connect == true ? enumConnect.CONNECTION : enumConnect.DISCONNECTION;
        }

        void RegisterEvent()
        {
            SocketDriver.onReceiveMessage += new agvcontroller.Driver.deleRcvMsg(SocketDriver_onReceiveMessage);
            SocketDriver.onConnect += new deleSocketReportConnect(SocketDriver_onConnect);
            
            Log.Info("RegisterEvent");
        }

        void SocketDriver_onConnect(object sender, enumConnect connect)
        {
            Connection = connect;

            if (onReportConnection != null)
                onReportConnection(this, connect);

            Log.Info("occuered Event Connent");
        }

        void SocketDriver_onReceiveMessage(object sender, string msg)
        {
            if (onRcvMsg != null)
                onRcvMsg(this, msg);

            //Log.Info("occuered Event Receive Message");
        }

        virtual public int SetVehicleJob(CVehicleJob vehicleJob)
        {
            //현재 진행 중인 Vehicle Job이 있으면 접수하지 않음.

            Log.Info("Receive new vehicle job");

            return CReturnCode.SUCCESS;
        }

        virtual public int SendMsg(string msg)
        {
            SocketDriver.Send(msg);

            Log.Info("Send Message");

            return CReturnCode.SUCCESS;
        }
    }

    public class CVehicleDic : Dictionary<int, CVehicle>
    {
        CAGVCDB AGVCDB;
        Logger Log;

        private static CVehicleDic uniqueInstance;

        public static CVehicleDic getInstance()
        {
            if (uniqueInstance == null)
            {
                uniqueInstance = new CVehicleDic();
            }
            return uniqueInstance;
        }

        public int InitMoudle()
        {
            int resurncode = CReturnCode.SUCCESS;
            
            foreach (KeyValuePair<int, CVehicle> vehicle in this)
            {
                resurncode = vehicle.Value.InitModule();
            }

            return CReturnCode.SUCCESS;
        }

        public CVehicleDic()
        {
            Log = new Logger("VehicleDic");

            GetDataFromDB();
        }

        public int AddVehicle(CVehicle vehicle)
        {
            this.Add(vehicle.ID,vehicle);

            return CReturnCode.SUCCESS;
        }

        virtual public int GetDataFromDB()
        {
            AGVCDB = CAGVCDB.getInstance();
            DataTable table = AGVCDB.AGVCDataSet.Tables["VehicleList"];
            CVehicle vehicle;

            try{
                    foreach(DataRow row in table.Rows)
                    {
                        vehicle = new CVehicle(Convert.ToString(row["Name"]));
                        vehicle.ID = Convert.ToInt32(row["ID"]);
                        vehicle.Use = Convert.ToBoolean(row["UseVehicle"]);
                        vehicle.CommType = Convert.ToString(row["CommType"]);
                        vehicle.EjectType = Convert.ToString(row["EjectType"]);
                        vehicle.GuideType = Convert.ToString(row["GuideType"]);
                        vehicle.BatteryLowLevel = Convert.ToInt32(row["BatteryLowLevel"]);
                        vehicle.CanForward = Convert.ToBoolean(row["CanForward"]);
                        vehicle.CanBackWard = Convert.ToBoolean(row["CanBackward"]);
                        vehicle.CanLeft = Convert.ToBoolean(row["CanLeft"]);
                        vehicle.CanRight = Convert.ToBoolean(row["CanRight"]);
                        vehicle.CanSideLeft = Convert.ToBoolean(row["CanSideLeft"]);
                        vehicle.CanSideRight = Convert.ToBoolean(row["CanSideRight"]);
                        vehicle.Port = Convert.ToInt32(row["Port"]);
                        vehicle.AGVCIP = IPAddress.Parse(Convert.ToString(row["AGVCIP"]));
                        vehicle.VehicleIP = IPAddress.Parse(Convert.ToString(row["VehicleIP"]));

                        vehicle.InitModule();

                        this.Add(vehicle.ID, vehicle);
                    }
                }
            catch (Exception ex)
            {
                Log.Exception(string.Format("{0},{1}", ex.Message, ex.StackTrace));
                return CReturnCode.ERR_DATA_ACQUIRING_FAIL;
            }
            return CReturnCode.SUCCESS;
        }

        virtual public void SetDataToDB()
        {
        }

        public CVehicle GetNext(CVehicle vehicle)
        {
            bool found = false;
            foreach(KeyValuePair<int , CVehicle> item in this)
            {
                if (found) return item.Value;

                if (item.Value.ID == vehicle.ID)
                {
                    found = true;
                }
            }

            return null;
        }

        public CVehicle GetPrev(CVehicle vehicle)
        {
            CVehicle prevVehicle = null;
            bool found = false;

            foreach (KeyValuePair<int, CVehicle> item in this)
            {
                if (item.Value.ID == vehicle.ID)
                {
                    found = true;
                }

                if (found) return prevVehicle;
                prevVehicle = item.Value;
            }

            return null;
        }
    }
}
